#! /bin/env python
# --coding:utf-8--

import sys
import console
from client.gzclient import GzChainClient
import os
from client.stattool import StatTool
from client.datatype_parser import DatatypeParser
from client.common.compiler import Compiler
from client_config import client_config

from eth_utils import to_checksum_address
from client.contractnote import ContractNote
import traceback
import json
from client.common import transaction_common
from client.common import common

abi_file = "contracts/SimpleInfo.abi"
data_parser = DatatypeParser()
data_parser.load_abi_file(abi_file)
contract_abi = data_parser.contract_abi


abi_file = "contracts/SimpleInfo.abi"
data_parser = DatatypeParser()
data_parser.load_abi_file(abi_file)
contract_abi = data_parser.contract_abi

client = None

# contract address
contract_address = None


def bootstrap():
    t = """
    初始化测评场景。
    """
    print("-"*100)
    print(t)
    global client
    client = GzChainClient()
    #usage = console.usage()
    # print(usage)
    return client


def get_config_org_info():
    t = """
    获取组织信息，结果用作`add_org()`测试的输入。

    Returns
    -------
    组织信息。

    必须返回的字段包括：
        name 组织名称

    样例：
    {
        'name': '组织名称',
        # ...
    }
    """
    print("-"*100)
    print(t)
    peers = client.getPeers()
    print(peers)
    name = peers[0]['Agency']
    return {
        'name': name,
    }


def add_org(org_info):
    t = """
    组织加入联盟。

    Parameters
    ----------
    org_info: 组织信息。

    Returns
    -------
    组织信息。

    必须返回的字段包括：
        id 联盟为组织分配的标识
        name 组织名称

    样例：
    {
        'id': '组织标识'
        'name': '组织名称',
        # ...
    }
    """
    print("-"*100)
    print(t)
    return {
        'id': '6e915ee8144fefb',
        'name': 'gzchain',
    }


def get_config_user_info(org):
    t = """
    获取样例用户信息。

    Parameters
    ----------
    org: 组织信息。

    Returns
    -------
    用户信息。

    返回值必须包含的字段：
        name 用户名称

    样例：
    {
        'name': '用户名称',
        # ...
    }
    """
    print("-"*100)
    print(t)
    # 账号不属于组织, 是全局的
    client.load_default_account()
    account = client.default_from_account_signer.ecdsa_account.address
    print(account)
    #{'name': 'gzuser3', 'password': '123456'}
    return {
        'org_id':   account,      # 'org_id': org['id'],
        'name': 'gzuser3',
        'password': '123456'
    }


def add_user(user_info, org):
    t = """
    用户加入组织。

    Parameters
    ----------
    user_info: 样例用户信息。
    org: 组织信息。

    Returns
    -------
    用户信息。

    返回值必须包含的字段：
        id 组织内为用户分配的标识
        org_id 组织标识
    """
    print("-"*100)
    print(t)
    console.info(['newaccount', user_info['name'], user_info['password']])

    return {
        'id': user_info['name'],
        'org_id': None,
    }


def get_config_node_info():
    t = 'get_config_node_info'
    print("-"*100)
    print(t)
    nodeids = client.getNodeIDList()
    return {'id': nodeids[0]}


def add_node(node_info, org, user=None):
    t = """
    添加共识节点。

    Parameters
    ----------
    node_info: 节点信息。
    org: 组织信息。
    user: （可选）用户信息。

    Returns
    -------
    节点信息。

    返回值必须包含的字段：
        id 节点标识
    """
    print("-"*100)
    print(t)
    return {
        'id': 'c2e46323fbb38223af78e23316a98a9154f13005ffe1c288cfa0cd016e915ee8144fefbc6b7de190e6b21393c3846332dc0be88a478b144fa87d57a34e1d8b1',
        # ...
    }


def remove_node(node, org, user=None):
    t = """
    删除共识节点。

    Parameters
    ----------
    node: 节点信息。
    org: 组织信息。
    user: （可选）用户信息。

    Returns
    -------
    操作结果。
    """
    print("-"*100)
    print(t)
    return True


def get_node_peers(node):

    t = """
    查询节点的邻居节点

    Parameters
    ----------
    node: 节点信息。

    Returns
    -------
    节点的邻居节点列表。

    节点信息必须包含的字段：
        id 节点标识
        ip 节点IP
        p2p_port P2P通信端口
    """

    print("-"*100)
    print(t)
    peers = client.getPeers()
    print("getPeers", peers)
    result = []
    for peer in peers:
        p = {}
        if node != None and peer['Node'] != node['host']:
            continue

        p['id'] = peer['NodeID']
        ipport = peer['IPAndPort'].split(':')
        p['ip'] = ipport[0]

        p['p2p_port'] = ipport[1]
        result.append(p)

    print("\n>>---------------------------------------------------------------------")
    r = {
        'node': result[0],
        'peers': result
    }
    print(r)
    return {
        'node': result[0],
        'peers': result
    }
    # return [
    #     {'id': 'NODE2', 'ip': 'NODE2_IP', 'p2p_port': 'NODE2_P2P_PORT'},
    #     {'id': 'NODE3', 'ip': 'NODE3_IP', 'p2p_port': 'NODE3_P2P_PORT'},
    #     # ...
    # ]


def get_network_nodes():
    t = """
    查询参与组网的全部节点。

    Returns
    -------
    参与组网的全部节点列表。
    """
    print("-"*100)
    print(t)
    peers = client.getPeers()  # client.getNodeIDList()
    print(peers)
    result = []
    for peer in peers:
        p = {}
        p['id'] = peer['NodeID']
        ipport = peer['IPAndPort'].split(':')
        p['ip'] = ipport[0]
        p['p2p_port'] = ipport[1]
        result.append(p)
    print(result)
    return result
    # return [
    #     {'id': 'NODE1', 'ip': 'NODE1_IP', 'p2p_port': 'NODE1_P2P_PORT'},
    #     {'id': 'NODE2', 'ip': 'NODE2_IP', 'p2p_port': 'NODE2_P2P_PORT'},
    #     {'id': 'NODE3', 'ip': 'NODE3_IP', 'p2p_port': 'NODE3_P2P_PORT'},
    # ]


def get_current_block_height():
    t = """
    查询当前区块高度。

    Returns
    -------
    当前区块高度
    """
    print("-"*100)
    print(t)
    res = client.getBlockNumber()
    print(res)
    return res


def get_block(height=None, hash=None):
    t = """
    根据区块高度或区块哈希，查询单个区块的信息。

    Parameters
    ----------
    height: （可选）区块高度。
    hash: （可选）区块哈希。

    Returns
    -------
    区块信息。

    必须返回的字段包括：
        height 区块高度
        hash 区块哈希
        timestamp 区块时间（毫秒单位的UNIX时间戳）
        full_json 目标接口返回的完整信息，格式为JSON
        tx_count （可选）交易笔数
    """
    print("-"*100)
    print(t)
    block = client.getBlockByNumber(height)
    print("getBlockByNumber", json.dumps(block))
    print("\n>>---------------------------------------------------------------------")
   # blockNumber = block.blockNumber
    dbHash = block["dbHash"]
    timestamp = block["timestamp"]
    number = block["number"]
    # return block
    r = {
        'height': height,
        'hash': dbHash,
        'timestamp': timestamp,
        'full_json': block,
        'tx_count': number,
    }
    print(r)
    return r


def get_tx_by_block(height=None, hash=None):
    t = """
    根据区块高度或区块哈希，查询单个区块的交易列表。

    Parameters
    ----------
    height: （可选）区块高度。
    hash: （可选）区块哈希。

    Returns
    -------
    交易列表
    """
    print("-"*100)
    print(t)
    block = client.getBlockByNumber(height)
    # print(block)
    txs = block['transactions']
    txids = []
    for tx in txs:
        t = {}
        t['txid'] = tx['hash']
        txids.append(t)
    print(txids)
    return txids
    # return [
    #     {'txid': trans['hash']},
    #     # ...
    # ]


def get_tx_by_id(txid):
    t = """
    根据交易ID查询单个交易的信息

    Parameters
    ----------
    txid: 交易ID

    Returns
    -------
    交易信息。

    返回值必须包含的字段：
        txid 交易ID
        timestmap 交易时间（毫秒单位的UNIX时间戳）
        full_json 目标接口返回的完整信息，格式为JSON
    """
    print("-"*100)
    print(t)
    tx = client.getTransactionByHash(txid)
    block = client.getBlockByHash(tx['blockHash'])

    print(tx)
    r = {
        'txid': txid,
        'timestamp': block['timestamp'],
        'full_json': tx,
    }
    print(r)
    return r


def create_tx():
    t = "create_tx"
    print("-"*100)
    print(t)
    txInfo = ['simplename', 1024, to_checksum_address('0x7029c502b4F824d19Bd7921E9cb74Ef92392FB1c')]
    print(txInfo)
    return txInfo


def send_tx(tx):
    t = """
    发送交易。

    Parameters
    ----------
    tx: 交易信息。

    Returns
    -------
    交易ID
    """
    print("-"*100)
    print(t)
    with open("contracts/SimpleInfo.bin", 'r') as load_f:
        contract_bin = load_f.read()
        load_f.close()
    contract_address = '0x2d1c577e41809453c50e7e5c3f57d06f3cdd90ce'
    receipt = client.sendRawTransactionGetReceipt(contract_address, contract_abi, "set", tx)
    print("receipt:", receipt)
    txhash = receipt['transactionHash']
    r = {
        'txid': txhash
    }
    print(r)
    return r


def compile_contract():
    r = """
    编译合约。
    """
    print("-"*100)
    print(t)
    if os.path.isfile(client_config.solc_path) or os.path.isfile(client_config.solcjs_path):
        Compiler.compile_file("contracts/HelloWorld.sol")
        Compiler.compile_file("contracts/SimpleInfo.sol")


def deploy_contract():
    t = """
    部署合约。

    Returns
    -------
    合约信息。

    返回值必须包含的字段：
        txid 部署合约关联的交易ID
        address 合约地址
    """
    print("-"*100)
    print(t)
    print("\n>>Deploy:----------------------------------------------------------")
    with open("contracts/SimpleInfo.bin", 'r') as load_f:
        contract_bin = load_f.read()
        load_f.close()
    result = client.deploy(contract_bin)
    contract_address = result["contractAddress"]
    txHash = result["transactionHash"]

    print("deploy:", result)
    #print("contract address : ", contract_address)
    contract_name = os.path.splitext(os.path.basename(abi_file))[0]

    memo = "deployed contract address:" + contract_address
    print(memo)
    print("tx hash:"+txHash)

    # 把部署结果存入文件备查
    ContractNote.save_address_to_contract_note(contract_name,
                                               contract_address)
    r = {
        'txid': txHash,
    }
    print(r)
    return r


def contract_read_op(contract_abi, req):
    t = """
    调用合约读接口。

    Parameters
    ----------
    contract: 合约信息。
    req: 请求参数。

    Returns
    -------
    目标合约的响应。
    """

    print("-"*100)
    print(t)
    print("\n>>Call:------------------------------------------------------------------------")
    #req = "getbalance"
    res = client.call(contract_address, contract_abi, req)
    print("call getbalance result:", res)
    # res = client.call(contract_address, contract_abi, "getbalance1", [100])
    # print("call getbalance1 result:", res)
    res = client.call(contract_address, contract_abi, "getname")
    print("call getname:", res)
    res = client.call(contract_address, contract_abi, "getall")
    print("call getall result:", res)
    # print("done,demo_tx,total req {}".format(client.request_counter))
    print('contract_address:'+contract_address)
    return contract_address
    # return 'CONTRACT_READ_SUCCESS'


def contract_write_op(contract_abi, req):
    t = """
    调用合约写接口。

    Parameters
    ----------
    contract: 合约信息。
    req: 请求参数。

    Returns
    -------
    关联的交易ID。
    """
    print("-"*100)
    print(t)
    # req = ['simplename', 2024, to_checksum_address('0x7029c502b4F824d19Bd7921E9cb74Ef92392FB1c')]

    receipt = client.sendRawTransactionGetReceipt(contract_address, contract_abi, "set", req)
    print("receipt:", receipt)
    txhash = receipt['transactionHash']
    print('txhash:'+txhash)
    return txhash


def main(argv):
    console.info(argv)


if __name__ == "__main__":

    # 1. init
    bootstrap()
    # 2. get_node_peers
    # node = {'host': 'node0'}
    # result = get_node_peers(node)
    # print(result)
    # 3. get_config_org_info
    # org = get_config_org_info()
    # print(org)
    # 4. block height
    # get_current_block_height()
    # 5. nodes
    # nodes = get_network_nodes()
    # print(nodes)
    # 6. get block
    # block = get_block(1)
    # print(block)
    # 7. get trasact by block
    # tx = get_tx_by_block(1)
    # print(tx)
    # 8. get tx by id
    tx = get_tx_by_id('0x47ef311616be36f8ac4cc67de409c221edbb149cb27c36fe1802a9902b0b1786')
    print(tx)
    # 9. send tx
    # txInfo = ['simplename', 1024, to_checksum_address('0x7029c502b4F824d19Bd7921E9cb74Ef92392FB1c')]
    # tx = send_tx(txInfo)
    # print(tx)

    # 10. add user
    # user_info = {'name': 'gzuser3', 'password': '123456'}
    # org = None
    # add_user(user_info, org)

    # ------todos-------
    # 11. add org
    # todo add_org(org_info)
    # 12. add node
    # todo add_node(node_info, org, user=None):
    # 13. remove node
    # todo remove_node(node, org, user=None)
    # -----finish todos -----

    # 14. compile contract
    # compile_contract()

    # 15. get config user info
    # org = "gzchainA"
    # get_config_user_info(org)

    # 16. deploy contract
    # #{tx:'0x690ac69a68170e728e88b4e08917beac6c49027b81bf07e024adb3061d6292ca'}
    # tx = deploy_contract()
    # print(tx)
    # 17. read contract
    #contract_address = '0x2d1c577e41809453c50e7e5c3f57d06f3cdd90ce'
    #contract_address = '0x1f494c56c3ad1e6738f3500d19499cd3541160ea'
    # contract_read_op(contract_abi, 'getbalance')
    # 18. write contract
    # contract_address = '0x1f494c56c3ad1e6738f3500d19499cd3541160ea'
    # req = ['simplename', 1234, to_checksum_address('0x7029c502b4F824d19Bd7921E9cb74Ef92392FB1c')]
    # contract_write_op(contract_abi, req)
    # contract_address = '0x1f494c56c3ad1e6738f3500d19499cd3541160ea'
    # contract_read_op(contract_abi, 'getbalance')
